/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.dolphinscheduler.api.controller;

import static org.apache.dolphinscheduler.common.constants.Constants.COMMA;
import static org.apache.dolphinscheduler.common.constants.Constants.HTTP_HEADER_UNKNOWN;
import static org.apache.dolphinscheduler.common.constants.Constants.HTTP_X_FORWARDED_FOR;
import static org.apache.dolphinscheduler.common.constants.Constants.HTTP_X_REAL_IP;

import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.constants.Constants;

import org.apache.commons.lang3.StringUtils;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

/**
 * base controller
 */
public class BaseController {

  /**
   * check params
   *
   * @param pageNo   page number
   * @param pageSize page size
   * @return check result code
   */
  // todo: directly throw exception
  public Result checkPageParams(int pageNo, int pageSize) {
    Result result = new Result();
    Status resultEnum = Status.SUCCESS;
    String msg = Status.SUCCESS.getMsg();
    if (pageNo <= 0) {
      resultEnum = Status.REQUEST_PARAMS_NOT_VALID_ERROR;
      msg = MessageFormat.format(Status.REQUEST_PARAMS_NOT_VALID_ERROR.getMsg(), Constants.PAGE_NUMBER);
    } else if (pageSize <= 0) {
      resultEnum = Status.REQUEST_PARAMS_NOT_VALID_ERROR;
      msg = MessageFormat.format(Status.REQUEST_PARAMS_NOT_VALID_ERROR.getMsg(), Constants.PAGE_SIZE);
    }
    result.setCode(resultEnum.getCode());
    result.setMsg(msg);
    return result;
  }

  /**
   * get ip address in the http request
   *
   * @param request http servlet request
   * @return client ip address
   */
  public static String getClientIpAddress(HttpServletRequest request) {
    String clientIp = request.getHeader(HTTP_X_FORWARDED_FOR);

    if (StringUtils.isNotEmpty(clientIp) && !clientIp.equalsIgnoreCase(HTTP_HEADER_UNKNOWN)) {
      int index = clientIp.indexOf(COMMA);
      if (index != -1) {
        return clientIp.substring(0, index);
      } else {
        return clientIp;
      }
    }

    clientIp = request.getHeader(HTTP_X_REAL_IP);
    if (StringUtils.isNotEmpty(clientIp) && !clientIp.equalsIgnoreCase(HTTP_HEADER_UNKNOWN)) {
      return clientIp;
    }

    return request.getRemoteAddr();
  }

  /**
   * return data list
   *
   * @param result result code
   * @return result code
   */
  public Result returnDataList(Map<String, Object> result) {
    Status status = (Status) result.get(Constants.STATUS);
    if (status == Status.SUCCESS) {
      String msg = Status.SUCCESS.getMsg();
      Object datalist = result.get(Constants.DATA_LIST);
      return success(msg, datalist);
    } else {
      Integer code = status.getCode();
      String msg = (String) result.get(Constants.MSG);
      return error(code, msg);
    }
  }

  /**
   * success
   *
   * @return success result code
   */
  public Result success() {
    Result result = new Result();
    result.setCode(Status.SUCCESS.getCode());
    result.setMsg(Status.SUCCESS.getMsg());

    return result;
  }

  /**
   * success does not need to return data
   *
   * @param msg success message
   * @return success result code
   */
  public Result success(String msg) {
    Result result = new Result();
    result.setCode(Status.SUCCESS.getCode());
    result.setMsg(msg);

    return result;
  }

  /**
   * return data no paging
   *
   * @param msg  success message
   * @param list data list
   * @return success result code
   */
  public Result success(String msg, Object list) {
    return getResult(msg, list);
  }

  /**
   * return data no paging
   *
   * @param list success
   * @return success result code
   */
  public Result success(Object list) {
    return getResult(Status.SUCCESS.getMsg(), list);
  }

  /**
   * return the data use Map format, for example, passing the value of key, value, passing a value
   * eg. "/user/add"  then return user name: zhangsan
   *
   * @param msg    message
   * @param object success object data
   * @return success result code
   */
  public Result success(String msg, Map<String, Object> object) {
    return getResult(msg, object);
  }

  /**
   * return data with paging
   *
   * @param totalList   success object list
   * @param currentPage current page
   * @param total       total
   * @param totalPage   total page
   * @return success result code
   */
  public Result success(Object totalList, Integer currentPage,
                        Integer total, Integer totalPage) {
    Result result = new Result();
    result.setCode(Status.SUCCESS.getCode());
    result.setMsg(Status.SUCCESS.getMsg());

    Map<String, Object> map = new HashMap<>(8);
    map.put(Constants.TOTAL_LIST, totalList);
    map.put(Constants.CURRENT_PAGE, currentPage);
    map.put(Constants.TOTAL_PAGE, totalPage);
    map.put(Constants.TOTAL, total);
    result.setData(map);
    return result;
  }

  /**
   * error handle
   *
   * @param code result code
   * @param msg  result message
   * @return error result code
   */
  public Result error(Integer code, String msg) {
    Result result = new Result();
    result.setCode(code);
    result.setMsg(msg);
    return result;
  }

  /**
   * put message to map
   *
   * @param result       result
   * @param status       status
   * @param statusParams object messages
   */
  protected void putMsg(Map<String, Object> result, Status status, Object... statusParams) {
    result.put(Constants.STATUS, status);
    if (statusParams != null && statusParams.length > 0) {
      result.put(Constants.MSG, MessageFormat.format(status.getMsg(), statusParams));
    } else {
      result.put(Constants.MSG, status.getMsg());
    }
  }

  /**
   * put message to result object
   *
   * @param result       result
   * @param status       status
   * @param statusParams status parameters
   */
  protected void putMsg(Result result, Status status, Object... statusParams) {
    result.setCode(status.getCode());

    if (statusParams != null && statusParams.length > 0) {
      result.setMsg(MessageFormat.format(status.getMsg(), statusParams));
    } else {
      result.setMsg(status.getMsg());
    }

  }

  /**
   * get result
   *
   * @param msg  message
   * @param list object list
   * @return result code
   */
  private Result getResult(String msg, Object list) {
    Result result = new Result();
    result.setCode(Status.SUCCESS.getCode());
    result.setMsg(msg);

    result.setData(list);
    return result;
  }
}
